package com.studio5704website.api.security;

import com.studio5704website.api.security.handler.DefaultAccessDeniedHandler;
import com.studio5704website.api.security.handler.DefaultNoAuthorizationHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import static java.util.Arrays.asList;

/**
 * @author 高威
 * Spring Security配置类
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private boolean h2ConsoleEnable;


    private AccessService accessService;

    private DefaultAccessDeniedHandler accessDeniedHandler;

    private DefaultNoAuthorizationHandler noAuthorizationHandler;

    @Autowired
    public WebSecurityConfig(RbacAuthorityService accessService,
                             @Value("${spring.h2.console.enabled:false}") boolean h2ConsoleEnable,
                             DefaultAccessDeniedHandler accessDeniedHandler,
                             DefaultNoAuthorizationHandler noAuthorizationHandler
                             ) {
        this.h2ConsoleEnable = h2ConsoleEnable;
        this.accessService = accessService;
        this.accessDeniedHandler = accessDeniedHandler;
        this.noAuthorizationHandler = noAuthorizationHandler;
    }

    @Bean
    public JwtTokenFilter jwtTokenFilter() {
        return new JwtTokenFilter();
    }



    @Override
    protected void configure(HttpSecurity http) throws Exception {
        if (h2ConsoleEnable) {
            http.authorizeRequests()
                    .antMatchers("/h2-console", "/h2-console/**").permitAll()
                    .and()
                    .headers().frameOptions().sameOrigin();
        }
        http.csrf().disable()
                .cors()
                .and()
                .exceptionHandling().authenticationEntryPoint(noAuthorizationHandler)
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers(HttpMethod.OPTIONS).permitAll()
                .anyRequest().access("@rbacAuthorityService.hasPermit(request, authentication)");
        http.exceptionHandling().accessDeniedHandler(accessDeniedHandler);

        http.addFilterBefore(jwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
    }
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        final CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(asList("*"));
        configuration.setAllowedMethods(asList("HEAD",
                "GET", "POST", "PUT", "DELETE", "PATCH"));
        configuration.setAllowCredentials(true);
        configuration.setAllowedHeaders(asList("Authorization", "Cache-Control", "Content-Type"));
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}
